import { useTableState } from "@/state/hopetoTable";
import { Table, TableColumnProps, TableProps } from "@arco-design/web-react";
import { useCallback, useEffect, useMemo, useRef } from "react";
import { EditableCell } from "./EditableCell";
import { keyboardKey2direction, moveXy, useColumns } from "./helper";
import styles from './index.module.scss';

export type ExtraColor = 'blue' | 'green' | 'yellow' | 'red' | 'gray' | string;

export interface IColumn<T = any> extends TableColumnProps<T> {
    /** 展示额外的信息 */
    extra?: string | ((col: any, item: T, index: number) => any);
    /**
     * 额外信息展示位置
     * @default bottomRight
     */
    extraPlacement?: 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
    /**
     * 额外信息展示颜色
     * @default blue
     */
    extraColor?: ExtraColor;
    /**
     * 是否可编辑
     * 可编辑时，可以通过单击选中一个单元格，双击进入编辑，键盘上下左右键移动到相邻可编辑单元格
     * 当选中单元格时，enter键进入编辑
     * 当处于编辑状态时，enter键退出编辑，并向下移动选中单元格
     */
    editable?: boolean;
    children?: IColumn[],
    //显示两个
    /** 展示额外的信息 */
    extra2?: string | ((col: any, item: T, index: number) => any);
    /**
     * 额外信息展示位置
     * @default topLeft
     */
    extraPlacement2?: 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
    /**
     * 额外信息展示颜色
     * @default red
     */
    extraColor2?: ExtraColor;
}

interface IProps extends TableProps {
    columns: IColumn[];
    /**
      * 单元格编辑结束触发，input输入值改变时触发
     * @param dataRow 当前渲染的数据行
     * @param dataKey 数据的key
     * @param val 编辑输入框的值
     * @param key 编辑行的key
     * @returns 
     */
    onCellEditChange?: (dataRow: number, dataKey: string, val: any, key: any) => void;
    /**
     * 输入框回车事件，进入下一行单元格进行编辑
     * @param dataRow 当前渲染的数据行
     * @param dataKey 数据的key
     * @param val 编辑输入框的值
     * @param key 编辑行的key
     * @returns 
     */
    onCellEditCompleted?: (dataRow: number, dataKey: string, val: any, key: any) => void;
}

const tableComps = {
    body: {
        cell: EditableCell,
    },
}

/**
 * 红袖自定义table
 */
const HopetoTable = (props: IProps) => {

    const tableId = useRef(`tid::${Date.now() * Math.random()}`);
    const {
        dataRef: tableStateRef,
        setFocusCell,
        setCellIsEditing
    } = useTableState(tableId.current);

    const {
        columns,
        onCellEditChange,
        onCellEditCompleted,
        data,
    } = props;

    // 单页最多展示行数
    const maxRow = useMemo(() => {
        if (typeof props.pagination === 'object') {
            return typeof props.pagination.pageSize === 'number' ? props.pagination.pageSize : (props.data?.length ? props.data!.length - 1 : 0);
        }
        return (props.data?.length ? props.data!.length - 1 : 0);
    }, [props.pagination, data]);

    // 可以编辑的表格列
    const editableCols = useMemo(() => {
        return columns.filter(col => !!col.editable).map(col => {
            if(col.children){
                return col.children.filter(col => !!col.editable).map(col => col.key || col.dataIndex) as string[];
            }else{
                return col.key || col.dataIndex
            }
        }).flat() as string[];
    }, [columns]);

    // 提供给cell组件的数据和方法
    const onCell = useCallback((a: any, index: number) => {
        if (editableCols.length === 0) return undefined;
        return {
            tableId: tableId.current,
            editableCols,
            dataIndex: index,
            onHandleSave: () => {},
            onEditChange: (val: any) => {
                const prev = tableStateRef.current.focusCell;
                onCellEditChange?.(prev[0], editableCols[prev[1]], val, a.key || a.ID );
            },
            onFinishEdit: (val: any) => {
                const prev = tableStateRef.current.focusCell;
                onCellEditCompleted?.(prev[0], editableCols[prev[1]], val, a.key);
                if (prev[0] < maxRow) {
                    setFocusCell([prev[0] + 1, prev[1]]);
                }
            }
        };
    }, [editableCols, onCellEditChange, onCellEditCompleted, maxRow]);

    const newColumns = useColumns(columns, onCell);

    // 是否有可编辑的表格项
    const hasEditableCell = useMemo(() => {
        return editableCols.length > 0 && !!props.data?.length && tableStateRef.current.focusCell[0] !== -1;
    }, [editableCols, props.data, tableStateRef.current.focusCell]);

    // 移动聚焦的表格项
    const moveFocusCell = useCallback((evt: KeyboardEvent) => {
        // 如果没有可编辑的表格项, 没有数据，或者没有聚焦的表格项，代表不能移动聚焦
        if (!hasEditableCell || tableStateRef.current.tableId !== tableId.current) return;
        const maxCol = editableCols.length - 1; // 最大列
        const prev = tableStateRef.current.focusCell;
        const moveDirection = keyboardKey2direction[evt.key as keyof typeof keyboardKey2direction];
        const newXy = moveXy(prev, moveDirection, [0, maxRow], [0, maxCol]);
        setFocusCell(newXy as [number, number]);
        // 当在编辑状态时，方向键禁止光标移动，方向键用于移动编辑单元格位置
        if (tableStateRef.current.cellIsEditing && moveDirection) {
            evt.preventDefault();
        }
    }, [hasEditableCell, maxRow]);

    // 进入编辑状态
    const enterEdit = useCallback((evt: KeyboardEvent) => {
        if (!hasEditableCell || tableStateRef.current.tableId !== tableId.current) return;
        // 存在聚焦
        if (evt.key === 'Enter') {
            // 正在编辑，移动到下一行
            if (tableStateRef.current.cellIsEditing) {
                const prev = tableStateRef.current.focusCell;
                if (prev[0] < maxRow) {
                    setFocusCell([prev[0] + 1, prev[1]]);
                }
                setCellIsEditing(false);
            } else {
                setCellIsEditing(true);
            }
        }
    }, [hasEditableCell, maxRow]);
    
    useEffect(() => {
        document.addEventListener('keydown', moveFocusCell);
        return () => {
            document.removeEventListener('keydown', moveFocusCell);
        }
    } , [moveFocusCell]);
    useEffect(() => {
        document.addEventListener('keydown', enterEdit);
        return () => {
            document.removeEventListener('keydown', enterEdit);
        }
    } , [enterEdit]);

    const tableComp = useMemo(() => {
        const {
            columns,
            onCellEditChange,
            ...rest
        } = props;
        return <Table 
            {...rest}
            columns={newColumns}
            components={tableComps}
            pagination={false}
        />;
    }, [newColumns, tableComps, props]);

    return (
        <div className={styles.hopetoTable}>
            {tableComp}
        </div>
    )    
}

export {
    HopetoTable
};

